package com.sunnada.demo.log;

import com.sunnada.demo.log.annotation.LogField;

import java.lang.annotation.Annotation;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @program: mybatisproject2
 * @description: 反射工具
 * @author: 李瑞益
 * @create: 2018-11-01 19:50
 **/
public class ReflectUtil {

    private final static Logger logger = LoggerFactory.getLogger(TrackLogUtil.class);

//    //region 获取数据
//    /**
//     * 根据传入对象获取dao对象
//     * @param object
//     * @param daoSuffix
//     * @return
//     */
//    public static Object getDaoByObj(Object object, String daoSuffix){
//        return getDao(object,null,daoSuffix);
//    }
//
//    /**
//     * 根据传入类名获取dao对象
//     * @param className
//     * @param daoSuffix  对于与dao层的后缀，如Repository、Dao等
//     * @return
//     */
//    public static Object getDaoByClassName(String className,String daoSuffix){
//        return getDao(null,className,daoSuffix);
//    }
//
//    /**
//     * 传入对象或类名获取dao对象
//     * @param object 不知名对象，确保他有对应dao层
//     * @param simpleClassName  类名（非全名）
//     * @param daoSuffix 对于与dao层的后缀，如Repository、Dao等
//     * @return
//     */
//    public static Object getDao(Object object, String simpleClassName , String daoSuffix) {
//        String name = "";
//        if(object != null ) {
//            Class<?> obj = object.getClass();
//            name = obj.getName();
//        }else{
//            if(simpleClassName.contains("Controller")){
//                name = simpleClassName.replace("Controller","");
//            }else if(simpleClassName.contains("Service")){
//                name = simpleClassName.replace("Service","");
//            }
//        }
//        //如果得到类名含有“.”，那么它可能是类全名，所以再获取一次类名
//        if(name.contains("."))
//            name = getSimpleClassName(name);
//        Object bean = null;
//        try {
//            //从IOC容器获取dao对象;
//            //这里，复合型名称如：lead Company
//
//            bean = SpringUtil.getBean(firstLetterToLowerCase(name) + daoSuffix);
//        } catch (Exception e) {
//            return bean;
//        }
//        return bean;
//    }
//
//    /**
//     * 传入不知名的实体对象，和id参数，获取数据库中的数据
//     * @param daoObj dao对象
//     * @param paramenter 参数对象
//     * @return
//     */
//    public static Object getDataById(Object daoObj,Object paramenter){
//        Class<?> daoCLass = daoObj.getClass();
//        Method[] methods = daoCLass.getMethods();
//        if (paramenter == null) {
//            logger.info("主键值无效");
//            return null;
//        }
//        Object[] objs = new Object[]{paramenter};
//        for(Method m : methods){
//            switch (m.getName()){
//                case "findById":
//                    return getData(daoObj,"findById",objs);
//                case "getById":
//                    return getData(daoObj,"getById",objs);
//                case "getPrimeryKey":
//                    //如果使用MyBatis的逆向工程生成的，方法名可能为这个
//                    return getData(daoObj,"getPrimeryKey",objs);
//                case "selectByPrimaryKey":
//                    //如果使用MyBatis的逆向工程生成的，方法名可能为这个
//                    return getData(daoObj,"selectByPrimaryKey",objs);
//            }
////            if(soapResult.getName().equalsIgnoreCase("findById")){
////                findName = soapResult.getName();
////                break;
////            }
////            else if(soapResult.getName().equalsIgnoreCase("getById")){
////                findName = soapResult.getName();
////                break;
////            }
//        }
////        return getData(daoObj,findName,paramenter);
//        return null;
//    }
//
//    /**
//     * 传入不知名的实体对象，和id参数，获取数据库中的数据
//     * @param daoObj
//     * @param MethodName 方法名
//     * @param paramenter 参数对象
//     * @return
//     */
//    public static Object getData(Object daoObj, String MethodName,Object paramenter){
//        Object value = null;//反射得到的值
//        try {
//            Class<?> daoClass = daoObj.getClass();
//            Method[] methods = daoClass.getMethods();
//            for(Method method : methods){
//                if(method.getName().equalsIgnoreCase(MethodName)){
//                    value = method.invoke(daoObj, paramenter);
//                    break;
//                }
//            }
//            //如果dao是继承于Repository的话，查询结果是Optional对象
//            if(value instanceof Optional){
//                if (((Optional) value).isPresent()) {
//                    value = ((Optional) value).get();
//                }
//            }
////            Method findById = daoClass.getMethod(MethodName, paramenterType);
////            value = findById.invoke(daoObj, paramenter);
//        } catch (IllegalAccessException e) {
//            e.printStackTrace();
//        } catch (InvocationTargetException e) {
//            e.printStackTrace();
//        }
//        return value;
//    }
//
//    /**
//     * 传入dao对象，和方法名， 参数集合得到返回值
//     * @param daoObj
//     * @param methodName
//     * @param paramenter
//     * @return
//     */
//    public static Object getData(Object daoObj, String methodName,Object[] paramenter){
//        Object value = null;//反射得到的值
//        try {
//            Class<?> daoClass = daoObj.getClass();
//            //这里遍历是为了得到参数类型
//            Method[] methods = daoClass.getMethods();
//            for(Method method : methods){
//                if(method.getName().equalsIgnoreCase(methodName)){
//                    //参数类型数组
//                    Class<?>[] paramTypes = method.getParameterTypes();
//                    //获取方法
//                    Method method1 = daoClass.getMethod(method.getName(), paramTypes);
//                    //参数类型格式化
//                    Object[] newObj = new Object[paramenter.length];
//                    //这里有两种，一是对象，二是非对象
//                    for (int i = 0 ; i < paramTypes.length ; i++) {
//                        if(isBaseDefaultType(paramTypes[i])){
//                            //基本类型
//                            newObj[i] = getBaseValueByType(paramTypes[i],paramenter[i]);
//                        }else{
//                            //对象
//                            newObj[i] = getActualField(paramTypes[i],paramenter[i]);
//                        }
//                    }
//                    value = method1.invoke(daoObj,newObj);
//
//                    break;
//                }
//            }
//            //如果dao是继承于Repository的话，查询结果是Optional对象
//            if(value instanceof Optional){
//                if (((Optional) value).isPresent()) {
//                    value = ((Optional) value).get();
//                }
//            }
//        } catch (IllegalAccessException e) {
//            e.printStackTrace();
//        } catch (InvocationTargetException e) {
//            e.printStackTrace();
//        } catch (NoSuchMethodException e) {
//            e.printStackTrace();
//        }
//        return value;
//    }
//    //endregion

    /**
     * 根据类名、方法名和注解类型获取方法上的注解
     * @param className 类全名
     * @param methodName 方法名
     * @param annotationClass 注解类
     * @return 注解对象 (可能为null）
     */
    public static Annotation getMethodAnnotaionByClassName(String className, String methodName, Class annotationClass){
        try {
            Class<?> aClass = Class.forName(className);
            Method[] methods = aClass.getMethods();//获取功能方法集合
            for(Method m : methods){
                if(m.getName().equals(methodName)){
                    Annotation annotation = m.getAnnotation(annotationClass);
                    if(annotation != null){
                        return annotation;
                    }
                    break;
                }
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 获取属性上的注解
     * @param field 属性对象
     * @param c 注解类
     * @return 注解对象（可能为null）
     */
    public static Annotation getAnnotation(AccessibleObject field, Class c){
        Annotation annotation = field.getAnnotation(c);
        if(annotation != null) {
            return annotation;
        }
        return null;
    }

    /**
     * 获取类名
     * @param declarName 全类名
     * @return 获取简化类名
     */
    public static String getSimpleClassName(String declarName){
        String name = "";
        //最后一个点，报名和类名的区分
        int index = declarName.lastIndexOf(".");
        if (index != -1) {
            name = declarName.substring(index + 1);
        }
        return name;
    }

    /**
     * 将类名首字母转小写
     * @param name 驼峰式命名规则的类名
     * @return 开头小写，符合驼峰命名的名称
     */
    public static String firstLetterToLowerCase(String name){
        String first = name.substring(0, 1);
        return first.toLowerCase()+name.substring(1);
    }

    /**
     * 获取传入对象get方法的键值（即公有属性）
     * @param obj 实体对象
     */
    public static Map<String,Object> getFieldAndValueFromEntity(Object obj){
        if (obj == null) {
            return null;
        }
        Class aClass = obj.getClass();
        Method[] methods = aClass.getMethods();
        Map<String,Object> map = new HashMap<>();
        //get 方法获取值
        try {
            for(Method m :methods){
                if(m.getName().contains("get")){
                    Method getMethod = aClass.getMethod(m.getName());
                    Object value = getMethod.invoke(obj);
                    //将对象属性和值存入map中
                    map.put(m.getName().replace("get",""),value);
                    System.out.println("获取的信息："+m.getName()+":"+value);
                }
            }
        } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
            e.printStackTrace();
        }
        return map;
    }

    /**
     * 获取传入对象的所有属性(包括私有）的键值
     * @param obj 实体对象
     * @return 属性字段的所以键值
     */
    public static Map<String,Object> getDeclaredFieldAndValue(Object obj){
        if (obj == null) {
            return null;
        }
        Class aClass = obj.getClass();
        Map<String,Object> map = new HashMap<>();
        try {
            Field[] fields = aClass.getDeclaredFields();
            for(Field f : fields) {
                //这里要打开对私有属性的访问，不然报错
                f.setAccessible(true);
                Object value = f.get(obj);
                map.put(f.getName(), value);
            }
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return  map;
    }

    /**
     * 获取不知名对象的id值
     *这里是以默认的@id注解为标准找的
     * @param obj 对象
     * @return id值
     */
    public static Object getId(Object obj){
        Class<?> objClass = obj.getClass();
        Object id = null;
        //先根据@Id这个注解去找
        try {
            Field[] fields = objClass.getDeclaredFields();
            for(Field field : fields){
                field.setAccessible(true);
                Object annoid = field.getAnnotation(LogField.class);
                if(annoid != null && ((LogField) annoid).primaryKey()){
                    id = field.get(obj);
                    return id;
                }
            }
            //如果没有找，可能为id
            if(id == null){
                Field field = objClass.getDeclaredField("id");
                //这里直接访问私有属性，打开权限
                field.setAccessible(true);
                id = field.get(obj);
                return id;
            }
        } catch (IllegalAccessException | NoSuchFieldException e) {
            e.printStackTrace();
        }
        return id;
    }

    /**
     * 判断是否属于基本类型
     * @param obj 对象
     * @return true：基本类型
     */
    public static boolean isBaseDefault(Object obj){
        return obj instanceof String || obj instanceof Integer || obj instanceof Double || obj instanceof Float
                || obj instanceof Byte || obj instanceof Long || obj instanceof Short || obj instanceof Character;
    }

    /**
     * 传入数据类型，判断是否是基本类型
     * @param type 对象类型
     * @return true：基本类型
     */
    public static boolean isBaseDefaultType(Class<?> type){
        return "java.lang.String".equals(type.getName()) || "java.lang.Integer".equals(type.getName()) ||
                "java.lang.Double".equals(type.getName()) || "java.lang.Float".equals(type.getName()) ||
                "java.lang.Byte".equals(type.getName()) || "java.lang.Long".equals(type.getName()) ||
                "java.Short".equals(type.getName());
    }

    /**
     * 根据传入的基本数据类型格式化数据
     * @param object 基本数据对象（没有类型的值）
     * @param type 数据类型
     */
    public static Object getBaseValueByType(Class<?> type,Object object){
        if ("java.lang.String".equals(type.getName())) {
            return object.toString();
        }
        if ("java.lang.Integer".equals(type.getName())) {
            return Integer.parseInt(object.toString());
        }
        if("java.lang.Double".equals(type.getName())) {
            return Double.parseDouble(object.toString());
        }
        if ("java.lang.Float".equals(type.getName())) {
            return Float.parseFloat(object.toString());
        }
        if("java.lang.Byte".equals(type.getName())) {
            return Byte.parseByte(object.toString());
        }
        if("java.lang.Long".equals(type.getName())) {
            return Long.parseLong(object.toString());
        }
        if("java.Short".equals(type.getName())) {
            return Short.parseShort(object.toString());
        }
        return null;
    }

    /**
     * 判断是否为基本类型的默认值
     * @param object 不知名对象
     * @return true：是基本类型默认值
     */
    public static boolean isBaseDefaultValue(Object object) {
        Class className = object.getClass();
        String strClassName = "" + className;
        if(className.equals(Integer.class)) {
            return (int)object == 0;
        } else if(className.equals(Byte.class)) {
            return (byte)object == 0;
        } else if(className.equals(Long.class)) {
            return (long)object == 0L;
        } else if(className.equals(Double.class)) {
            return (double)object == 0.0d;
        } else if(className.equals(Float.class)) {
            return (float)object == 0.0f;
        } else if(className.equals(Character.class)) {
            return (char)object == '\u0000';
        } else if(className.equals(Short.class)) {
            return (short)object == 0;
        } else if(className.equals(Boolean.class)) {
            return !((boolean) object);
        }
        return false;
    }

    /**
     * 通过setter、getter方法名获取属性名称
     *
     * @param methodName 方法名
     * @return 字段名
     */
    public static String getFieldNameForMethod(String methodName){
        String fieldName = "";
        if (methodName.startsWith("get")) {
            fieldName = methodName.replaceFirst("get","");
        }else if(methodName.startsWith("set")){
            fieldName = methodName.replaceFirst("set","");
        }
        return firstLetterToLowerCase(fieldName);
    }

    /**得到object对象正真的类型对象*/
    public static <T> T getActualField(Class<T> c,Object object){
        return (T)object;
    }

}
